`include "defines.v"

module id_exe (
    input wire                              clk,
    input wire                              rst,

    input wire                              stall_i,
    input wire                              flush_i,

    input wire [`RAM_ADDR_WIDTH - 1 : 0]    inst_addr_i,
    input wire [`INST_WIDTH - 1: 0]         inst_i,

    input wire                              rd_w_ena_i,
    input wire [4 : 0]                      rd_w_addr_i,
    input wire                              csr_w_ena_i,
    input wire [11: 0]                      csr_w_addr_i,
    input wire [`REG_BUS]                   op1_i,
    input wire [`REG_BUS]                   op2_i,
    input wire [`REG_BUS]                   op3_i,

    input wire[`ALU_SEL_BUS]                alu_sel_i,
    input wire                              alu_sub_flag_i,
    input wire                              alu_word_flag_i,
    input wire                              alu_symbol_flag_i,

    input wire                              transfer_en_i,
    input wire[`TRANSFER_SEL_BUS]           transfer_sel_i,

    input wire                              mem_load_en_i,
    input wire                              mem_store_en_i,
    input wire[`MEM_SEL_BUS]                mem_sel_i,

    // input wire                              csr_en_i,
    input wire[`CSR_SEL_BUS]                csr_sel_i,

    input wire[`RD_SEL_BUS]                 rd_sel_i,

    input wire [`REG_BUS]                   exception_type_i,
    input wire                              valid_i,

    output reg [`RAM_ADDR_WIDTH - 1 : 0]    inst_addr_o,
    output reg [`INST_WIDTH - 1: 0]         inst_o,

    output reg                              rd_w_ena_o,
    output reg [4 : 0]                      rd_w_addr_o,
    output reg                              csr_w_ena_o,
    output reg [11: 0]                      csr_w_addr_o,
    output reg [`REG_BUS]                   op1_o,
    output reg [`REG_BUS]                   op2_o,
    output reg [`REG_BUS]                   op3_o,

    output reg [`ALU_SEL_BUS]               alu_sel_o,
    output reg                              alu_sub_flag_o,
    output reg                              alu_word_flag_o,
    output reg                              alu_symbol_flag_o,

    output reg                              transfer_en_o,
    output reg [`TRANSFER_SEL_BUS]          transfer_sel_o,

    output reg                              mem_load_en_o,
    output reg                              mem_store_en_o,
    output reg [`MEM_SEL_BUS]               mem_sel_o,

    // output reg                              csr_en_o,
    output reg [`CSR_SEL_BUS]               csr_sel_o,

    output reg [`RD_SEL_BUS]                rd_sel_o,

    output reg [`REG_BUS]                   exception_type_o,
    output reg                              valid_o
);
    always @(posedge clk) begin
        if(rst == 1'b1) begin
            inst_addr_o         <= 0;
            inst_o              <= 0;

            rd_w_ena_o          <= 1'b0;
            rd_w_addr_o         <= 5'h0;
            csr_w_ena_o         <= 1'b0;
            csr_w_addr_o        <= 12'h0;
            op1_o               <= `ZERO_WORD;
            op2_o               <= `ZERO_WORD;
            op3_o               <= `ZERO_WORD;

            alu_sel_o           <= 0;
            alu_sub_flag_o      <= 0;
            alu_word_flag_o     <= 0;
            alu_symbol_flag_o   <= 0;

            transfer_en_o       <= 0;
            transfer_sel_o      <= 0;

            mem_load_en_o       <= 0;
            mem_store_en_o      <= 0;
            mem_sel_o           <= 0;

            // csr_en_o            <= 0;
            csr_sel_o           <= 0;

            rd_sel_o            <= 0;

            exception_type_o    <= `ZERO_WORD;
            valid_o             <= 1'b0;
        end
        else begin
            if(stall_i == 1'b1) begin
                inst_addr_o         <= inst_addr_o;
                inst_o              <= inst_o;

                inst_addr_o         <= inst_addr_o;

                rd_w_ena_o          <= rd_w_ena_o;
                rd_w_addr_o         <= rd_w_addr_o;
                csr_w_ena_o         <= csr_w_ena_o;
                csr_w_addr_o        <= csr_w_addr_o;
                op1_o               <= op1_o;
                op2_o               <= op2_o;
                op3_o               <= op3_o;

                alu_sel_o           <= alu_sel_o;
                alu_sub_flag_o      <= alu_sub_flag_o;
                alu_word_flag_o     <= alu_word_flag_o;
                alu_symbol_flag_o   <= alu_symbol_flag_o;

                transfer_en_o       <= transfer_en_o;
                transfer_sel_o      <= transfer_sel_o;

                mem_load_en_o       <= mem_load_en_o;
                mem_store_en_o      <= mem_store_en_o;
                mem_sel_o           <= mem_sel_o;

                // csr_en_o            <= csr_en_o;
                csr_sel_o           <= csr_sel_o;

                rd_sel_o            <= rd_sel_o;

                exception_type_o    <= exception_type_o;
                valid_o             <= valid_o;
            end
            else if(flush_i == 1'b1) begin
                inst_addr_o         <= 0;
                inst_o              <= 0;

                rd_w_ena_o          <= 1'b0;
                rd_w_addr_o         <= 5'h0;
                csr_w_ena_o         <= 1'b0;
                csr_w_addr_o        <= 12'h0;
                op1_o               <= `ZERO_WORD;
                op2_o               <= `ZERO_WORD;
                op3_o               <= `ZERO_WORD;

                alu_sel_o           <= 0;
                alu_sub_flag_o      <= 0;
                alu_word_flag_o     <= 0;
                alu_symbol_flag_o   <= 0;

                transfer_en_o       <= 0;
                transfer_sel_o      <= 0;

                mem_load_en_o       <= 0;
                mem_store_en_o      <= 0;
                mem_sel_o           <= 0;

                // csr_en_o            <= 0;
                csr_sel_o           <= 0;

                rd_sel_o            <= 0;

                exception_type_o    <= `ZERO_WORD;
                valid_o             <= 1'b0;
            end 
            else begin
                inst_addr_o         <= inst_addr_i;
                inst_o              <= inst_i;

                inst_addr_o         <= inst_addr_i;

                rd_w_ena_o          <= rd_w_ena_i;
                rd_w_addr_o         <= rd_w_addr_i;
                csr_w_ena_o         <= csr_w_ena_i;
                csr_w_addr_o        <= csr_w_addr_i;
                op1_o               <= op1_i;
                op2_o               <= op2_i;
                op3_o               <= op3_i;

                alu_sel_o           <= alu_sel_i;
                alu_sub_flag_o      <= alu_sub_flag_i;
                alu_word_flag_o     <= alu_word_flag_i;
                alu_symbol_flag_o   <= alu_symbol_flag_i;

                transfer_en_o       <= transfer_en_i;
                transfer_sel_o      <= transfer_sel_i;

                mem_load_en_o       <= mem_load_en_i;
                mem_store_en_o      <= mem_store_en_i;
                mem_sel_o           <= mem_sel_i;

                // csr_en_o            <= csr_en_i;
                csr_sel_o           <= csr_sel_i;

                rd_sel_o            <= rd_sel_i;

                exception_type_o    <= exception_type_i;
                valid_o             <= valid_i;
            end
        end 
    end
endmodule
